//
// Created by songpingwang on 25-7-8.
//

#include <utility>
#include <limits>
#include "UDataBase.h"
#include "UDataFrame.h"
#include <iostream>
#include <unordered_set>
#include "UDataView.h"
#include "charset_utils.h"


namespace NDFrame {
    UDataFrame::UDataFrame(const size_t capacity) {
        this->m_capacity = capacity;
        allocate(capacity);
    }

    UDataFrame::UDataFrame(const std::initializer_list<DataItem> items) {
        this->m_size = items.size();
        this->m_capacity = this->m_size;
        allocate(this->m_capacity);
        std::copy(items.begin(), items.end(), this->ItemPtr.get());
    }

    UDataFrame::UDataFrame(
        const int idx,
        const int x0, const int y0,
        const int x1, const int y1,
        const int width, const int height,
        const int page, const int flags,
        std::string &&text, std::string &&text_sep) {
        this->m_size = 1;
        this->m_capacity = 1;
        allocate(this->m_capacity);
        this->ItemPtr.get()[0] = DataItem(
            idx, x0, y0, x1, y1,
            width, height, page, flags,
            std::move(text), std::move(text_sep));
    }


    UDataFrame::UDataFrame(const UDataFrame &other) : m_size(other.m_size), m_capacity(other.m_capacity),
                                                      ItemPtr(nullptr) {
        if (m_capacity > 0) {
            allocate(m_capacity);
            std::copy_n(other.ItemPtr.get(), m_size, this->ItemPtr.get());
        }
    }

    void UDataFrame::swap_data_frame(UDataFrame &other) noexcept {
        std::swap(this->m_size, other.m_size);
        std::swap(this->m_capacity, other.m_capacity);
        std::swap(this->ItemPtr, other.ItemPtr);
    }

    UDataFrame::UDataFrame(UDataFrame &&other) noexcept {
        this->ItemPtr = std::move(other.ItemPtr);
        this->m_size = other.m_size;
        this->m_capacity = other.m_capacity;
        other.m_size = 0;
        other.m_capacity = 0;
    }


    /* 复制赋值运算符 */
    UDataFrame &UDataFrame::operator=(const UDataFrame &other) {
        if (this != &other) {
            UDataFrame temp(other);
            swap_data_frame(temp);
        }
        return *this;
    }

    /* 移动赋值运算符 */
    UDataFrame &UDataFrame::operator=(UDataFrame &&other) noexcept {
        if (this != &other) {
            swap_data_frame(other);
            other.m_size = 0;
            other.m_capacity = 0;
            other.ItemPtr.reset();
        }
        return *this;
    }

    void UDataFrame::clear() {
            if (this->ItemPtr) {
                std::fill_n(this->ItemPtr.get(), this->m_size, DataItem{});
            }
            this->m_size = 0;
        }

    void UDataFrame::allocate(const size_t new_capacity) {
        this->ItemPtr = std::shared_ptr<DataItem[]>(new DataItem[new_capacity], std::default_delete<DataItem[]>());
        this->m_capacity = new_capacity;
    }

    void UDataFrame::deallocate() {
        this->ItemPtr.reset();
        this->m_size = 0;
        this->m_capacity = 0;
    }

    VOID_USE void UDataFrame::push_back(const DataItem &item) {
        if (this->m_size == this->m_capacity) {
            reserve(this->m_capacity == 0 ? 1 : this->m_capacity * 2);
        }
        this->ItemPtr.get()[this->m_size++] = item;
    }

    VOID_USE void UDataFrame::push_back(DataItem &&item) {
        if (this->m_size == this->m_capacity) {
            reserve(this->m_capacity == 0 ? 1 : this->m_capacity * 2);
        }
        this->ItemPtr.get()[this->m_size++] = std::move(item);
    }

    const DataItem &UDataFrame::operator[](const size_t index) const {
        if (index >= this->m_size) {
            throw std::out_of_range("Index out of range");
        }
        return this->ItemPtr.get()[index];
    }

    DataItem &UDataFrame::operator[](const size_t index) {
        if (index >= this->m_size) {
            throw std::out_of_range("Index out of range");
        }
        return this->ItemPtr.get()[index];
    }

    template<Field field>
    auto &UDataFrame::ix(const size_t row) {
        if (row >= m_size) {
            throw std::out_of_range("Row index out of range");
        }
        return ItemPtr.get()[row].ValueField<field>();
    }

    template<Field field>
    const auto &UDataFrame::ix(const size_t row) const {
        if (row >= m_size) {
            throw std::out_of_range("Row index out of range");
        }
        return ItemPtr.get()[row].ValueField<field>();
    }

    void UDataFrame::reserve(const size_t new_capacity) {
        if (new_capacity <= this->m_capacity) {
            return;
        }

        auto new_ptr = std::shared_ptr<DataItem[]>(new DataItem[new_capacity], std::default_delete<DataItem[]>());
        if (this->ItemPtr) {
            for (size_t i = 0; i < this->m_size; ++i) {
                new_ptr.get()[i] = std::move(this->ItemPtr.get()[i]);
            }
        }

        this->ItemPtr = new_ptr;
        this->m_capacity = new_capacity;
    }

    DataItem &UDataFrame::back() override {
        if (this->empty()) {
            throw std::out_of_range("UDataFrame is empty");
        }
        return this->ItemPtr.get()[this->m_size - 1];
    }

    DataItem &UDataFrame::front() override {
        if (this->empty()) {
            throw std::out_of_range("UDataFrame is empty");
        }
        return this->ItemPtr.get()[0];
    }


    //////////////////////////////////////////////////////////////////////////////
    ////					  对应字段值： 对df.txt 进行行合并
    //////////////////////////////////////////////////////////////////////////////
    /**
    *  merge_line    对UDataFrame进行合并行:
    *  双指针算法 (Two-Pointer Algorithm) 一个“读指针” (read_idx) 遍历整个数组，一个“写指针” (write_idx) 指向下一个有效数据应该被写入的位置。
    *  合并条件：      限定宽(width)与高(height)， （下一行的x0与本行的x1的绝对距离小于width)，(下一行的y0与本行的y0的绝对距离小于height)
    *  符合合并条件的： 将本行与下一行text使用sep字符进行合并，(x0,y0)取这两行最小值,(x1,y1,height)取这两行最小大值, 并删除下一行
    */
    UDataFrame UDataFrame::DF_merge_line(const int width, const int height, const std::string_view sep) {
        if (this->m_size < 2) {
            return *this;
        }

        // 1. 创建一个新Frame，用于存放合并后的结果
        UDataFrame mergedFrame;
        mergedFrame.reserve(this->m_size);

        // 2. 将第一个元素先放入新Frame
        mergedFrame.push_back(this->ItemPtr.get()[0]);

        // 3. 使用双指针思想，从第二个元素开始遍历
        for (size_t read_idx = 1; read_idx < this->m_size; ++read_idx) {
            // mergedFrame.back() 是我们正在构建的“当前行”
            DataItem& current = mergedFrame.ItemPtr.get()[mergedFrame.m_size - 1];
            const DataItem& next_to_check = this->ItemPtr.get()[read_idx];

            if (std::abs(next_to_check.x0 - current.x1) < width && std::abs(next_to_check.y0 - current.y0) < height) {
                // 条件满足，合并 next_to_check 到 current
                current.text.reserve(current.text.length() + sep.length() + next_to_check.text.length());
                current.text += sep;
                current.text += next_to_check.text;

                current.x0 = std::min(current.x0, next_to_check.x0);
                current.y0 = std::min(current.y0, next_to_check.y0);
                current.x1 = std::max(current.x1, next_to_check.x1);
                current.y1 = std::max(current.y1, next_to_check.y1);
                current.width = current.x1 - current.x0;
                current.height = std::max(current.height, next_to_check.height);
            } else {
                // 条件不满足，将 next_to_check 作为一个新行添加到结果中
                mergedFrame.push_back(next_to_check);
            }
        }

        return mergedFrame;
    }


    void UDataFrame::reset_index() noexcept {
        if (this->empty()) {
            return;
        }
        const auto& thisPtr = ItemPtr.get();

        for (size_t i = 0; i < this->m_size; ++i) {
            thisPtr[i].idx = static_cast<int>(i);
        }
    }


    UDataFrame UDataFrame::DF_pointers_to_df(const VecItemPtr &pointers) const {
        if (pointers.empty() || this->empty()) {
            return UDataFrame{};
        }

        const std::unordered_set<const DataItem *> pointers_set(pointers.begin(), pointers.end());
        const size_t valid_pointer_count = pointers_set.size();

        UDataFrame newFrame(valid_pointer_count);
        const auto newPtr = newFrame.getItemPtr();
        const auto thisPtr = this->ItemPtr.get();

        size_t j = 0;
        for (size_t i = 0; i < m_size && j < valid_pointer_count; ++i) {
            if (pointers_set.count(&thisPtr[i])) {
                newPtr[j] = thisPtr[i];
                newPtr[j].idx = static_cast<int>(j);
                j++;
            }
        }
        newFrame.m_size = j;
        return newFrame;
    }


    //////////////////////////////////////////////////////////////////////////////
    ////					  删除函数
    //////////////////////////////////////////////////////////////////////////////
    UDataFrame UDataFrame::DF_drop_pointer(const VecItemPtr &pointers) const {
        if (pointers.empty()) {
            return *this;
        }
        std::unordered_set<DataItem*> valid_drop_set;
        const auto thisPtr = ItemPtr.get();

        for (auto* ptr : pointers) {
            if (ptr >= thisPtr && ptr < thisPtr + m_size) {
                valid_drop_set.insert(ptr);
            }
        }

        if (valid_drop_set.empty()) {
            return *this;
        }

        const size_t actual_drop_count = valid_drop_set.size();
        const size_t new_size = m_size - actual_drop_count;

        UDataFrame newFrame(new_size);
        const auto newPtr = newFrame.getItemPtr();

        size_t j = 0;
        for (size_t i = 0; i < m_size; ++i) {
            if (valid_drop_set.count(&thisPtr[i]) == 0) {
                newPtr[j] = thisPtr[i];
                newPtr[j].idx = static_cast<int>(j);
                j++;
            }
        }

        newFrame.m_size = new_size;
        return newFrame;
    }


    void UDataFrame::drop_pointer(const VecItemPtr &pointers) {
        if (pointers.empty()) { return;}
        const auto data_start = ItemPtr.get();
        const auto data_end = data_start + m_size;
        std::unordered_set<DataItem *> valid_drop_set;
        for (auto ptr : pointers) {
            if (!ptr) continue;
            if (ptr >= data_start && ptr < data_end) {
                valid_drop_set.insert(ptr);
            }
        }

        size_t new_size = 0;
        for (size_t i = 0; i < m_size; ++i) {
            if (valid_drop_set.find(&data_start[i]) == valid_drop_set.end()) {
                data_start[new_size] = std::move(data_start[i]);
                data_start[new_size].idx = static_cast<int>(new_size);
                new_size++;
            }
        }

        for (size_t i = new_size; i < m_size; ++i) {
            data_start[i].~DataItem();
        }

        m_size = new_size;
    }


    UDataFrame UDataFrame::concat(const UDataFrame& df1, const UDataFrame& df2) {
        const size_t total_size = df1.size() + df2.size();
        UDataFrame result(total_size + 5);
        std::copy_n(df1.getItemPtr(), df1.size(), result.getItemPtr());
        std::copy_n(df2.getItemPtr(), df2.size(), result.getItemPtr() + df1.size());
        return result;
    }


    //////////////////////////////////////////////////////////////////////////////
    ////				   通用函数 对应字段值进行过滤
    //////////////////////////////////////////////////////////////////////////////
    template<typename Predicate>
    bool UDataFrame::filter(VecItemPtr& out_pointers, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
                      "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");

        out_pointers.clear();
        if (this->empty()) {
            return false;
        }

        out_pointers.reserve(this->size());
        const auto thisPtr = this->ItemPtr.get();
        for (size_t i = 0; i < this->m_size; ++i) {
            if (predicate(thisPtr[i])) {
                out_pointers.push_back(&thisPtr[i]);
            }
        }
        return !out_pointers.empty();
    }

    template<typename Predicate>
    UDataFrame UDataFrame::DF_filter(Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
                      "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");

        UDataFrame result;
        if (this->empty()) {
            return result;
        }
        result.reserve(this->size());
        const auto thisPtr = this->ItemPtr.get();
        for (size_t i = 0; i < this->m_size; ++i) {
            if (predicate(thisPtr[i])) {
                result.push_back(thisPtr[i]);
            }
        }
        return result;
    }


    template<typename Predicate>
    UDataFrame UDataFrame::DF_xyxy_impl(Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem &>,
      "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");
        UDataFrame result(this->m_capacity > 3 ? 3 : this->m_capacity);
        const auto& thisPtr = ItemPtr.get();

        for (size_t i = 0; i < this->m_size; ++i) {
            if (predicate(thisPtr[i])) {
                result.push_back(thisPtr[i]);
            }
        }
        return result;
    }


    //////////////////////////////////////////////////////////////////////////////
    ////			   使用索引进行筛选
    //// DF_iloc 返回副本(深复制)
    //// DV_iloc 返回视图(无复制)
    //////////////////////////////////////////////////////////////////////////////
    UDataFrame UDataFrame::DF_iloc(const int idx0, const int idx1) const {
        if (idx0 < 0 || idx1 >= static_cast<int>(this->m_size) || idx0 > idx1) {
            throw std::out_of_range("Index range out of bounds");
        }
        const auto& thisPtr = ItemPtr.get();

        UDataFrame result(idx1 - idx0 + 1);
        for (int i = idx0; i < idx1; ++i) {
            result.push_back(thisPtr[i]);
        }
        return result;
    }

    MAYBE_USE UDataView UDataFrame::DV_iloc(const int idx0, const int idx1) const {
        return UDataView{*this, static_cast<size_t>(idx0), static_cast<size_t>(idx1)};
    }


    bool UDataFrame::iloc(VecItemPtr &out_ptr, const int idx0, const int idx1) const {
        if (idx0 < 0 || idx1 >= static_cast<int>(this->m_size) || idx0 > idx1) {
            std::wcout << "Index range out of bounds\n";
            return false;
        }
        if (out_ptr.empty()) { out_ptr.reserve(7); }
        const auto& thisPtr = ItemPtr.get();

        for (size_t i = 0; i < this->m_size; ++i) {
            if (thisPtr[i].idx >= idx0 && thisPtr[i].idx < idx1) {
                out_ptr.push_back(&thisPtr[i]);
            }
        }
        return !out_ptr.empty();
    }


    template<typename ConditionInt>
    UDataView UDataFrame::DV_loc(ConditionInt conditionInt) const {
        if (this->m_size == 0) return UDataView{*this, 0, 0};

        const auto& thisPtr = ItemPtr.get();
        size_t startIndex = this->m_size;

        for (size_t i = 0; i < this->m_size; ++i) {
            if (conditionInt(thisPtr[i])) {
                if (startIndex == this->m_size) {
                    startIndex = i;
                }
            } else {
                if (startIndex != this->m_size) {
                    return UDataView{*this, startIndex, i};
                }
            }
        }

        if (startIndex != this->m_size) {
            return UDataView{*this, startIndex, this->m_size};
        }

        return UDataView{*this, 0, 0};
    }


    MAYBE_USE UDataView UDataFrame::DV_loc_xyxy(int x0, int y0, int x1, int y1) const {
        return DV_loc([x0, y0, x1, y1](const DataItem &item) {
            return item.x0 > x0 && item.y0 > y0 && item.x1 < x1 && item.y1 < y1;
        });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_x0x1(int x0, int x1) const {
        return DV_loc([x0, x1](const DataItem &item) noexcept { return item.x0 > x0 && item.x1 < x1; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_y0y1(int y0, int y1) const {
        return DV_loc([y0, y1](const DataItem &item) noexcept { return item.y0 > y0 && item.y1 < y1; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_x0y0_grate(int x0, int y0) const {
        return DV_loc([x0, y0](const DataItem &item) noexcept { return item.x0 > x0 && item.y0 > y0; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_x0y0_less(int x0, int y0) const {
        return DV_loc([x0, y0](const DataItem &item) noexcept { return item.x0 < x0 && item.y0 < y0; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_x1y1_less(int x1, int y1) const {
        return DV_loc([x1, y1](const DataItem &item) noexcept { return item.x1 < x1 && item.y1 < y1; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_x0_grate(int x0) const {
        return DV_loc([x0](const DataItem &item) noexcept { return item.x0 > x0; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_x0_less(int x0) const {
        return DV_loc([x0](const DataItem &item) noexcept { return item.x0 < x0; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_x1_less(int x1) const {
        return DV_loc([x1](const DataItem &item) noexcept { return item.x1 < x1; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_y0_grate(int y0) const {
        return DV_loc([y0](const DataItem &item) noexcept { return item.y0 > y0; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_y0_less(int y0) const {
        return DV_loc([y0](const DataItem &item) noexcept { return item.y0 < y0; });
    }

    MAYBE_USE UDataView UDataFrame::DV_loc_y1_less(int y1) const {
        return DV_loc([y1](const DataItem &item) noexcept { return item.y1 < y1; });
    }
}
